iT邦幫忙

2021 iThome 鐵人賽

DAY 21
1

若在開發時想要在請求到達Controller 前或回應離開Controller 後執行一些業務邏輯,比如進入Controller 前判斷是否已經登入或是是否有請求路徑的訪問權限等功能,可以使用過濾器或攔截器兩個方法進行處理。

Filter 過濾器

Filter 是Web Server 的一部份,不是Spring 框架自帶的,所以我們可以HTTP 請求到達Servlet 前或在HTTP 回應回傳給Client 端前進行攔截,攔截成功就可以實作一些自定義的業務邏輯或對回應資料進行修改,而Spring Security 就是一個很好的Filter 實作方法,可以透過Spring Security 配置進行授權與認證等功能。

常用註釋

  1. @Order : 表示過濾順序,其值越小越優先執行。
  2. @WebFilter : 宣告這是一個過濾器類別,Spring 會根據其屬性配置過濾器,主要屬性如下。
    1. filterName : 指定Filter 名稱。
    2. value : 指定攔截路徑,與urlPatterns 擇一使用。
    3. urlPatterns : 指定攔截路徑,與value 擇一使用。
    4. servletNames : 設定Filter 過濾哪些Servlet 的請求。
    5. dispatcherTypes : 設定Filter 過濾哪種請求方式,屬性有ASYNC、ERROR、FORWARD、INCLUDE、REQUEST,預設為全選。
    6. initParams : 設定Filter 初始化參數。
    7. asyncSupported : 設定Filter 是否支援異步模式,預設為false。
    8. description : 描述Filter 用途。
    9. displayName : 指定Filter 顯示名稱。

實作

建立一個LoginFilter

要建立一個Filter 有兩種常見的方法,一種是實作javax.servlet.Filter 介面,另一種則是繼承org.springframework.web.filter.OncePerRequestFilter 類別,使用方法上基本差不多,這邊就僅展示實作javax.servlet.Filter 介面的方法。

package com.example.iThomeIronMan.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.example.iThomeIronMan.model.Member;

@Component
@WebFilter(filterName = "", urlPatterns = {"/*"})
@Order(value = 1)
public class LoginFilter implements Filter {

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// TODO Auto-generated method stub

		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;

		HttpSession session = req.getSession();
		Member member = (Member) session.getAttribute("MemberSession");

		String uri = new String(req.getRequestURI());

		// 放行所有靜態檔案
		if(uri.contains("/css") || uri.contains("/images") || uri.contains("/js")) {
			chain.doFilter(request, response);
			return ;
		}

		// 已登入
		if(member != null) {
			System.err.println("Been Login");
			if(uri.contains("/login") || uri.contains("/register")) {
				res.sendRedirect("/information");
			}
			else {
				chain.doFilter(request, response);
			}
		}
		// 未登入
		else {
			System.err.println("No Login");
			if(uri.contains("/login") || uri.contains("/register")) {
				chain.doFilter(request, response);
			}
			else {
				res.sendRedirect("/login");
			}
		}
	}

}

啟動類別新增@ServletComponentScan 註釋

注意使用@WebServlet、@WebFilter、@WebListener 等Servlet 註釋時需要在Spring Boot 的啟動類別上添加@ServletComponentScan 註釋,否則不會生效。

package com.example.iThomeIronMan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class IThomeIronManApplication {

	public static void main(String[] args) {
		SpringApplication.run(IThomeIronManApplication.class, args);
	}

}

參考網站

spring-boot實現增加自定義filter(新)
SpringBoot基於註解方式配置Filter
SpringBoot中使用Filter丶Java教程网-IT开发者们的技术天堂


上一篇
Day 20 - Spring Boot & Session
下一篇
Day 22 - Spring Boot & Interceptor
系列文
誤打誤撞學了Spring Boot 還當了後端工程師30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言